package cn.ljn.basic.service.impl;

import cn.ljn.basic.constant.BaseConstants;
import cn.ljn.basic.dto.BinderDto;
import cn.ljn.basic.dto.LoginDto;
import cn.ljn.basic.dto.WxChatDto;
import cn.ljn.basic.jwt.JwtUtils;
import cn.ljn.basic.jwt.RsaUtils;
import cn.ljn.basic.jwt.UserInfo;
import cn.ljn.basic.service.LoginService;
import cn.ljn.basic.util.AjaxResult;
import cn.ljn.basic.util.BusinessException;
import cn.ljn.basic.util.HttpUtil;
import cn.ljn.basic.util.MD5Utils;
import cn.ljn.system.domain.Menu;
import cn.ljn.system.mapper.MenuMapper;
import cn.ljn.system.mapper.PermissionMapper;
import cn.ljn.user.domain.Logininfo;
import cn.ljn.user.domain.User;
import cn.ljn.user.domain.Wxuser;
import cn.ljn.user.mapper.LogininfoMapper;
import cn.ljn.user.mapper.UserMapper;
import cn.ljn.user.mapper.WxuserMapper;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.security.PrivateKey;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

@Service
public class LoginServiceImpl implements LoginService {
    @Autowired
    private RedisTemplate redisTemplate;

    @SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection")
    @Autowired
    private LogininfoMapper logininfoMapper;

    @SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection")
    @Autowired
    private WxuserMapper wxuserMapper;

    @SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection")
    @Autowired
    private UserMapper userMapper;

    @SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection")
    @Autowired
    private PermissionMapper permissionMapper;

    @SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection")
    @Autowired
    private MenuMapper menuMapper;

    @Value("${jwt.pri}")
    private String jwtPri;



    @Override
    /**
     * 账号密码登录
     */
    public AjaxResult account( LoginDto loginDto) {

        Logininfo logininfo = logininfoMapper.findByAccount(loginDto);
        if (null == logininfo) {
            throw new BusinessException("未注册！！！");
        }
        // 验证密码是否正确
        String password = logininfo.getPassword();  // 后端查出来的密码
        String dtoPassword = loginDto.getPassword(); // 参数密码
        // 颜值密码  加密 在判断
        String encrypByMd5 = MD5Utils.encrypByMd5(logininfo.getSalt() + dtoPassword);
        if (!password.equals(encrypByMd5)) {
            throw new BusinessException("账号密码错误");
        }
        // 生成uuid作为redis的key 也就是token
        Map<String, Object> result = getMap(logininfo);
        return AjaxResult.me().success(result);
    }

    /**
     * 微信登录
     */
    @Override
    public AjaxResult wechat(WxChatDto dto) {
        //校验参数
        // 调用第二个接口：获取token和openid
        String jsonStr = HttpUtil.httpGet(String.format(BaseConstants.WechatConstant.SECOND_INTER, BaseConstants.WechatConstant.APPID, BaseConstants.WechatConstant.SECRET, dto.getWxCode()));
        // 将json字符串转换成json对象
        JSONObject jsonObject = JSONObject.parseObject(jsonStr);
        // 从jsonObject中获取token和openid
        String access_token = jsonObject.getString("access_token");
        String openId = jsonObject.getString("openid");
        // 通过openid查询wxuser表
        Wxuser wxuser = wxuserMapper.findByOpenId(openId);
        Logininfo logininfo = new Logininfo();
        // 3.有数据就跳转到登录页面
        if (wxuser != null && wxuser.getUserId() != null) {
            logininfo = logininfoMapper.findByUserId(wxuser.getUserId());
            // 保存至redis中 key：token value：logininfo
            // 将logininfo中的敏感字段进行置空
            Map<String, Object> map = getMap(logininfo);
            // 返回至前端
            return AjaxResult.me().success(map);
        }
        // 4.没有数据就跳转到绑定
        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append("?accessToken=")
                .append(access_token)
                .append("&openId=")
                .append(openId);

        return AjaxResult.me().fail("nobinder").setResultObj(stringBuilder.toString());
    }

    /**
     * 微信绑定
     */
    @Override
    public AjaxResult binder(BinderDto dto) {
        //校验参数
        //判断手机验证码是否正确
        String smsCode = (String) redisTemplate.opsForValue().get(String.format(BaseConstants.BINDER_REDIS_KEY, dto.getPhone()));
        if(StringUtils.isBlank(smsCode) || !smsCode.equals(dto.getVerifyCode())){
                    throw new BusinessException("验证码错误");
        }
        // 调用第三个接口
        String jsonStr = HttpUtil.httpGet(String.format(BaseConstants.WechatConstant.THIRD_INTER,dto.getAccessToken(),dto.getOpenId()));
        // 将json字符串转换为json对象
        Wxuser wxuser = JSONObject.parseObject(jsonStr, Wxuser.class);
        // 4.判断user中是否有数据
        User user = userMapper.findByPhone(dto.getPhone());
        Logininfo logininfo = new Logininfo();
        if (user == null) {
            // 4.2 没有的话添加三张表
            user = dto.getUser();
            BeanUtils.copyProperties(user, logininfo);
            logininfo.setType(1);
            logininfo.setDisable(true);
            logininfoMapper.add(logininfo);
            user.setLogininfoId(logininfo.getId());
            userMapper.add(user);
        }
        wxuser.setUserId(user.getId());
        wxuserMapper.add(wxuser);

        logininfo = logininfoMapper.findByUserId(wxuser.getUserId());
        Map<String, Object> map = getMap(logininfo);
        // 返回至前端
        return AjaxResult.me().success(map);
    }


    /**
     * jwt登录方案
     * */
    private Map<String, Object> getMap(Logininfo logininfo) {
        Map<String, Object> map = new HashMap<>();
        try {
            // 创建UserInfo实体（因为生成jwt传的方法里面需要这个实体）
            UserInfo userInfo = new UserInfo();
            // 将用户数据set进去
            userInfo.setLogininfo(logininfo);
            // 获取私钥
            PrivateKey privateKey = RsaUtils.getPrivateKey(JwtUtils.class.getClassLoader().getResource(jwtPri).getFile());
            if (logininfo.getType() == 0){ // 判断是否是后台用户
                // 是后台用户 应该存在 permission 和 menu
                // 根据logininfo查询permissin
                List<String> permissions = permissionMapper.findByLogininfoId(logininfo.getId());
                // 根据logininfo查询menu
                List<Menu> menus = menuMapper.findByLogininfoId(logininfo.getId());

                userInfo.setPermissions(permissions);
                userInfo.setMenus(menus);

                map.put("permissions", permissions);
                map.put("menus", menus);
            }
            // 根据私钥获取token(jwt串) 私钥是用于给尾巴加密
            String token = JwtUtils.generateTokenExpireInSeconds(userInfo, privateKey, 3000000);
            // 将logininfo中的敏感字段进行置空
            logininfo.setPhone(null);
            logininfo.setPassword(null);

            // 返回给前端
            map.put("token", token);
            map.put("logininfo", logininfo);

        } catch (Exception e) {
            e.printStackTrace();
        }
        return map;
    }


}
